package fr.umlv.ig.metroView.map;

import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelEvent;

import javax.swing.JLayeredPane;
import javax.swing.SwingUtilities;

import fr.umlv.ig.layout.JLayeredPaneLayout;
import fr.umlv.ig.model.MetroModelImpl;
import fr.umlv.ig.model.Train;

/**
 * The Map of our application. It's a {@link JLayeredPane} composed by two level.
 * The first level represents the train and the other in background represents
 * the map with line and station. 
 * 
 * In this Map you can selected and remove trains.
 * You can also open or close a station.
 * 
 * @author jenseric
 * @author william
 *
 */
@SuppressWarnings("serial")
public class MetroMap extends JLayeredPane {

	/**
	 * The map with stations and lines.
	 */
	private final MetroMapStations metroMapStations;
	/**
	 * The map with the trains.
	 */
	private final MetroMapTrains metroMapTrains;
	
	/**
	 * The current selected Train.
	 */
	public Train currentSelected;

	/**
	 * The current scale of the Map.
	 */
	private double scale = 1;
	
	/**
	 * The current translation in abscissa when the scale is 1.
	 */
	private double translateX=0;
	
	/**
	 * The current translation not in abscissa when the scale is 1.
	 */
	private double translateY=0;
	
	/**
	 * The coordinate x on click.
	 */
	private double xOnClick;
	/**
	 * The coordinate y on click.
	 */
	private double yOnClick;
	
	/**
	 * The current translation X on click
	 */
	private double translationXOnClick;
	
	/**
	 * The current translation Y on click.
	 */
	private double translationYOnClick;

	/**
	 * Initializes a {@link MetroMap} with a metroModel.
	 * @param metroModel the metroModel used to draw the metro.
	 */
	public MetroMap(MetroModelImpl metroModel) {
		super();
		setLayout(new JLayeredPaneLayout());
		this.metroMapStations = new MetroMapStations(metroModel);
		this.metroMapTrains = new MetroMapTrains(scale, translateX, translateY, metroModel);
		metroMapTrains.setOpaque(false);
		metroMapTrains.setPreferredSize(new Dimension(900,650));
		metroMapTrains.setVisible(true);
		metroMapTrains.addMouseWheelListener(mouseAdapterForScale());
		metroMapTrains.addMouseListener(mouseAdapterForTranslation());
		metroMapTrains.addMouseListener(mouseAdapterForClick());

		add(metroMapTrains,Integer.valueOf(2));

		metroMapStations.drawMap(scale, translateX, translateY);
		metroMapStations.setOpaque(true);
		metroMapStations.setPreferredSize(new Dimension(900,650));
		metroMapStations.setVisible(true);

		add(metroMapStations,Integer.valueOf(1));
		setVisible(true);
	}

	/**
	 * Returns {@link MouseAdapter} for the user click.
	 * @return {@link MouseAdapter} for the user click.
	 */
	private MouseAdapter mouseAdapterForClick() {
		return new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if(SwingUtilities.isLeftMouseButton(e)) {
					metroMapStations.onLeftClick(e,scale, translateX, translateY);
				}
				if(SwingUtilities.isRightMouseButton(e)) {
					metroMapStations.onRightClick(e,scale, translateX, translateY);
				}
			}
		};
	}

	
	/**
	 * Returns {@link MouseAdapter} for the zoom.
	 * @return {@link MouseAdapter} for the zoom.
	 */
	private MouseAdapter mouseAdapterForScale() {
		return new MouseAdapter() {
			@Override
			public void mouseWheelMoved(MouseWheelEvent e) {
				if(e.getWheelRotation()<0) {
					scale +=0.2;
				}
				else {
					if(scale<0.6) {
						scale = 0.6;
						return;
					}
					scale -=0.2;
				}

				metroMapStations.zoom(e,scale, translateX, translateY);
				metroMapTrains.zoom(e, scale, translateX, translateY);

				metroMapStations.repaint();
				metroMapTrains.repaint();
			}

		};
	}

	/**
	 * Returns MouseAdapter for the translation.
	 * @return {@link MouseAdapter} for the translation.
	 */
	private MouseAdapter mouseAdapterForTranslation() {
		return new MouseAdapter() {

			private final MouseMotionAdapter mouseAdapter = new MouseMotionAdapter() {
				@Override
				public void mouseDragged(MouseEvent e) {
					double x = translationXOnClick + ((double)e.getX()-xOnClick)/scale;
					double y = translationYOnClick + ((double)e.getY()-yOnClick)/scale;
					metroMapStations.translate(scale,x,y ); 
					metroMapTrains.translate(e, scale, x, y);

					metroMapStations.repaint();
					metroMapTrains.repaint();
				}
			};

			@Override
			public void mousePressed(MouseEvent e) {
				translationXOnClick = translateX;
				translationYOnClick = translateY;
				xOnClick = e.getX();
				yOnClick = e.getY();
				metroMapTrains.addMouseMotionListener(mouseAdapter);
			}

			@Override
			public void mouseReleased(MouseEvent e) {
				translateX +=  ((double)e.getX()-xOnClick)/scale;
				translateY +=  ((double)e.getY()-yOnClick)/scale;
				metroMapTrains.removeMouseMotionListener(mouseAdapter);
			}
		};
	}



}
